package com.hongji.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hongji.model.BidKeyword;
import com.hongji.model.RawBidInfo;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class JsonFileReader {
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final int MAX_RETRIES = 1;  // 最大重试次数
    private static final int RETRY_DELAY_MS = 1000;  // 每次重试之间的延迟，单位毫秒

    // 读取文件的核心方法
    public static List<RawBidInfo> readFromFile(File file) {
        if (!file.exists() || !file.canRead()) {
            log.error("文件不可访问: {}", file.getAbsolutePath());
            return Collections.emptyList();
        }

        List<RawBidInfo> mainList = readFileWithRetry(file, MAX_RETRIES);
        if (mainList == null) {
            log.error("读取主文件失败, 且未能重试成功: {}", file.getAbsolutePath());
            return Collections.emptyList();
        }

        // 判断文件是否包含有效数据并筛选
        return processFileContent(file, mainList);
    }

    // 处理文件内容：筛选有效数据
    private static List<RawBidInfo> processFileContent(File file, List<RawBidInfo> mainList) {
        // 检查文件是否为空列表
        if (mainList == null || mainList.isEmpty()) {
            log.warn("⚠ 警告：文件内容为空列表（需检查爬取脚本） => 路径: {}，文件名: {}", file.getAbsolutePath(), file.getName());
            return Collections.emptyList();
        }

        // 判断文件是否包含有效数据
        boolean hasValidData = mainList.stream().anyMatch(JsonFileReader::isValidBid);  // 判断是否存在有效数据
        if (!hasValidData) {
            log.warn("⚠ 警告：文件无有效数据（可能格式不兼容） => 路径: {}，文件名: {}", file.getAbsolutePath(), file.getName());
            return Collections.emptyList();
        }

        // 筛选有效数据并返回
        return mainList.stream()
                .filter(JsonFileReader::isValidBid)  // 筛选掉无效数据
                .filter(item -> containsAnyKeyword(item.getTitle(), BidKeyword.getAllKeywords()))  // 关键词过滤
                .filter(JsonFileReader::filterByDateAndDeadline)  // 日期筛选（发布日期为昨天/截止日期大于3天）
                .collect(Collectors.toList());
    }

    // 文件遍历并按任务分组
    public static Map<String, List<File>> collectJsonFiles(String rootDirs) {
        Map<String, List<File>> taskFilesMap = new HashMap<>();

        String[] paths = rootDirs.split(",");
        for (String rootDirPath : paths) {
            try {
                Files.walk(Paths.get(rootDirPath))
                        .filter(path -> path.toString().endsWith(".json"))
                        .forEach(path -> {
                            File file = path.toFile();
                            String taskDir = file.getParentFile().getName();
                            taskFilesMap.computeIfAbsent(taskDir, k -> new ArrayList<>()).add(file);
                        });
            } catch (IOException e) {
                log.error("遍历目录时发生错误", e);
            }
        }

        return taskFilesMap;
    }

    // 处理文件并保存到数据库
    public static void processFilesAndSaveToDB(String rootDirs, Connection conn) {
        Map<String, List<File>> taskFilesMap = collectJsonFiles(rootDirs);

        taskFilesMap.values().stream()
                .flatMap(List::stream)  // 扁平化 List<File> 为单个 File 流
                .forEach(file -> {
                    List<RawBidInfo> list = readFromFile(file);  // 读取并处理文件
                    if (!list.isEmpty()) {
                        saveToDatabase(conn, list);  // 保存到数据库
                    }
                });
    }

    // 保存有效数据到数据库
    private static void saveToDatabase(Connection conn, List<RawBidInfo> list) {
        String sql = "INSERT INTO raw_bid_info (title, url, raw_publish_text, end_raw_publish_text) VALUES (?, ?, ?, ?)";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            for (RawBidInfo info : list) {
                if (info.getTitle() != null && !info.getTitle().isEmpty() &&
                        info.getUrl() != null && !info.getUrl().isEmpty() &&
                        ((info.getRawPublishText() != null && !info.getRawPublishText().isEmpty())
                                || (info.getEndRawPublishText() != null && !info.getEndRawPublishText().isEmpty()))) {

                    ps.setString(1, info.getTitle());
                    ps.setString(2, info.getUrl());
                    ps.setString(3, info.getRawPublishText());
                    ps.setString(4, info.getEndRawPublishText());
                    ps.addBatch();
                }
            }
            ps.executeBatch();
            log.info("数据成功批量保存到数据库");
        } catch (SQLException e) {
            log.error("保存数据到数据库失败: {}", e.getMessage(), e);
        }
    }

    // 筛选数据，确保它们包含有效的标题、URL 和发布日期
    private static boolean isValidBid(RawBidInfo item) {
        // Step 1: 统一处理 publishText
        String publishText = firstNonEmpty(
                item.getRawPublishText(),
                (item.getEndRawPublishText() == null &&
                        item.getRawPublishTextDate() == null &&
                        item.getRawPublishTextYear() == null) ? extractPublishTextFromTitle(item.getTitle()) : null,
                (item.getRawPublishTextYear() != null &&
                        item.getRawPublishTextDate() != null) ? getDanteString(item) : null
        );

        if (publishText != null && !publishText.isEmpty()) {
            item.setRawPublishText(publishText);
        }

        // Step 2: 处理 endRawPublishText 格式化
        String endPublishText = item.getEndRawPublishText();
        if (endPublishText != null && !endPublishText.isEmpty()) {
            item.setEndRawPublishText(extractPublishTextFromTitle(endPublishText));
        }

        // Step 3: 尝试从 rawPublishText 提取标准日期
        String dateText = extractDate(item.getRawPublishText());
        if (dateText != null && !dateText.isEmpty()) {
            item.setRawPublishText(dateText);
        }

        // Step 4: 最终有效性判断
        boolean hasTitle = item.getTitle() != null && !item.getTitle().isEmpty();
        boolean hasUrl = item.getUrl() != null && !item.getUrl().isEmpty();
        boolean hasAnyDate = (item.getRawPublishText() != null && !item.getRawPublishText().isEmpty()) ||
                (item.getEndRawPublishText() != null && !item.getEndRawPublishText().isEmpty());

        return hasTitle && hasUrl && hasAnyDate;
    }

    /**
     * 返回第一个非空非空字符串的值（类似 Optional.orElse）
     */
    private static String firstNonEmpty(String... candidates) {
        for (String str : candidates) {
            if (str != null && !str.isEmpty()) {
                return str;
            }
        }
        return null;
    }


    private static String getDanteString(RawBidInfo item) {
        String year = item.getRawPublishTextYear().trim();
        String date = item.getRawPublishTextDate().trim();

        String publishDate = year + "-" + date;

        // 使用 StringBuilder 来优化性能
        StringBuilder sb = new StringBuilder(publishDate);

        // 一次性替换多个字符
        String formattedDate = sb.toString()
                .replaceAll("[\\.\\/年月日]", "-")  // 替换 '.', '/', '年', '月', '日' 为 '-'
                .replaceAll(" ", "");               // 去除空格

        // 确保日期部分是两位数（例如：1月1日 -> 01-01）
        formattedDate = formattedDate.replaceAll("-(\\d{1})-(\\d{1})", "-0$1-0$2");
        return formattedDate;
    }

    // 日期格式化处理，返回 String 类型
    private static String extractDate(String text) {
        if (text == null || text.isEmpty()) {
            return null;
        }

        List<Pattern> patterns = Arrays.asList(
                Pattern.compile("(\\d{4})[-年](\\d{1,2})[-月](\\d{1,2})日?"),  // yyyy-MM-dd
                Pattern.compile("(\\d{4})/(\\d{1,2})/(\\d{1,2})"),  // yyyy/MM/dd
                Pattern.compile("(\\d{4})年(\\d{1,2})月(\\d{1,2})日"),  // yyyy年MM月dd日
                Pattern.compile("(\\d{1,2})/(\\d{1,2})/(\\d{4})"),  // MM/dd/yyyy
                Pattern.compile("(\\d{4})-(\\d{1,2})-(\\d{1,2}) (\\d{1,2}:\\d{1,2}:\\d{1,2})")  // yyyy-MM-dd HH:mm:ss
        );

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                try {
                    String year = matcher.group(1);
                    String month = matcher.group(2);
                    String day = matcher.group(3);

                    return String.format("%s-%02d-%02d",
                            year,
                            Integer.parseInt(month),
                            Integer.parseInt(day)); // 返回格式化后的日期字符串
                } catch (Exception e) {
                    // 如果无法解析，继续尝试下一个模式
                    log.warn("日期解析失败, 使用下一个模式尝试", e);
                }
            }
        }

        return null; // 未能提取有效日期
    }

    private static boolean filterByDateAndDeadline(RawBidInfo item) {
        String publishText = item.getRawPublishText();
        String publishDate = item.getRawPublishText();  // 直接使用格式化后的日期

        // 检查发布时间
        try {
            if (publishText != null && !publishText.isEmpty()) {
                // 如果发布时间是昨天
                LocalDate publishLocalDate = LocalDate.parse(publishDate);  // 这里直接解析已经格式化的日期
                if (publishLocalDate.equals(LocalDate.now().minusDays(1))) {
                    return true;  // 发布时间是昨天
                }
            }
        } catch (Exception e) {
            log.error(item.toString(), e);
        }


        // 检查截止日期（如果存在）
        String endPublishText = item.getEndRawPublishText();
        if (endPublishText != null && !endPublishText.isEmpty()) {
            // 如果截止日期存在，直接使用格式化后的日期进行比较
            LocalDate endLocalDate = LocalDate.parse(endPublishText);  // 直接解析已经格式化的截止日期
            // 截止日期距离当前日期大于3天
            return endLocalDate.isAfter(LocalDate.now().plusDays(3)); // 截止日期大于3天
        }

        return false; // 不符合条件
    }

    // 检查标题中是否包含任何关键词
    private static boolean containsAnyKeyword(String title, List<String> keywords) {
        if (title == null || title.isEmpty() || keywords == null || keywords.isEmpty()) {
            return false;
        }
        return keywords.stream().anyMatch(title::contains);
    }

    private static String extractPublishTextFromTitle(String title) {
        String[] patterns = {
                "\\d{4}[-/.年]\\d{1,2}[-/.月]\\d{1,2}[日]?",  // 2024-06-01、2024/6/1、2024年6月1日
                "\\d{4}[-/.年]\\d{1,2}[月]?",  // 2024-06、2024年6月
                "\\d{4}年"  // 仅匹配年份
        };

        for (String pattern : patterns) {
            Matcher matcher = java.util.regex.Pattern.compile(pattern).matcher(title);
            if (matcher.find()) {
                return matcher.group();
            }
        }

        return null;
    }

    // 封装读取文件的重试机制
    private static List<RawBidInfo> readFileWithRetry(File file, int retries) {
        List<RawBidInfo> result = null;
        int attempt = 0;

        while (attempt <= retries) {
            try {
                result = mapper.readValue(file, mapper.getTypeFactory()
                        .constructCollectionType(List.class, RawBidInfo.class));
                log.info("成功读取文件: {}", file.getAbsolutePath());
                break;  // 成功读取后跳出循环
            } catch (Exception e) {
                attempt++;
                log.error("尝试读取文件失败 (尝试次数 {}): {}", attempt, file.getAbsolutePath(), e);
                if (attempt <= retries) {
                    try {
                        Thread.sleep(RETRY_DELAY_MS);  // 延迟再重试
                    } catch (InterruptedException ie) {
                        log.error("重试延迟中断: {}", ie.getMessage());
                    }
                }
            }
        }

        return result;  // 如果成功读取，返回数据，否则返回 null
    }
}
